package com.xinqi.modules.sys.stats.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.core.enums.CourseContentTypeEnum;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.sys.stats.convert.ClassTeachingDayStConvert;
import com.xinqi.modules.sys.stats.domain.ClassTeachingDayStEntity;
import com.xinqi.modules.sys.stats.domain.SchoolTeachingDayStEntity;
import com.xinqi.modules.sys.stats.dto.req.ClassTeachingDayStCreateDTO;
import com.xinqi.modules.sys.stats.dto.req.ClassTeachingDayStDeleteDTO;
import com.xinqi.modules.sys.stats.dto.req.ClassTeachingDayStQueryDTO;
import com.xinqi.modules.sys.stats.dto.req.ClassTeachingDayStUpdateDTO;
import com.xinqi.modules.sys.stats.dto.req.ClassTeachingOverviewQueryDTO;
import com.xinqi.modules.sys.stats.dto.rsp.ClassOverviewResultDTO;
import com.xinqi.modules.sys.stats.dto.rsp.ClassTeachingCountResultDTO;
import com.xinqi.modules.sys.stats.dto.rsp.ClassTeachingDayStResultDTO;
import com.xinqi.modules.sys.stats.manager.ClassTeachingDayStManager;
import com.xinqi.modules.sys.stats.manager.SchoolTeachingDayStManager;
import com.xinqi.modules.sys.stats.service.ClassTeachingDayStService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 班级教学数据统计服务层实现
 *
 * @author: wenjie
 * @date: 2023/08/24
 */
@Validated
@Service("classTeachingDayStService")
@RequiredArgsConstructor
public class ClassTeachingDayStServiceImpl implements ClassTeachingDayStService {
    private final ClassTeachingDayStConvert classTeachingDayStConvert;
    private final ClassTeachingDayStManager classTeachingDayStManager;
    private final SchoolTeachingDayStManager schoolTeachingDayStManager;

    /**
     * 分页查询 班级教学数据统计数据
     */
    @Override
    public PageInfo<ClassTeachingDayStResultDTO> page(Param pageable, ClassTeachingDayStQueryDTO query) {
        LocalDateTime startTime = query.getStatDate().atTime(LocalTime.MIN);
        LocalDateTime endTime = query.getEndDate().atTime(LocalTime.MAX);
        IPage<ClassTeachingDayStResultDTO> page = classTeachingDayStManager.findPage(Pages.page(pageable), query.getSchoolName(), startTime, endTime);

        this.setActivitySort(page.getRecords(), query);
        return Pages.convert(page);
    }

    private void setActivitySort(List<ClassTeachingDayStResultDTO> records, ClassTeachingDayStQueryDTO query) {
        if (CollectionUtils.isNotEmpty(records)) {
            List<ClassTeachingCountResultDTO> todaySortList = classTeachingDayStManager.findContentSortListAndDateRange(query.getSchoolName(), query.getStatDate().atTime(LocalTime.MIN), query.getEndDate().atTime(LocalTime.MAX));

            LocalDateTime prevStartTime = query.getStatDate().minusDays(ChronoUnit.DAYS.between(query.getStatDate(), query.getEndDate()) + 1).atTime(LocalTime.MIN);
            LocalDateTime prevEndTime = query.getStatDate().minusDays(1).atTime(LocalTime.MAX);
            List<ClassTeachingCountResultDTO> yesterdaySortList = classTeachingDayStManager.findContentSortListAndDateRange(query.getSchoolName(), prevStartTime, prevEndTime);

            Map<Long, Integer> todaySortedMap = IntStream.range(0, todaySortList.size()).boxed().collect(Collectors.toMap(i -> todaySortList.get(i).getClassId(), i -> i + 1));
            Map<Long, Integer> yesterdaySortedMap = IntStream.range(0, yesterdaySortList.size()).boxed().collect(Collectors.toMap(i -> yesterdaySortList.get(i).getClassId(), i -> i + 1));
            if (CollectionUtils.isEmpty(yesterdaySortList)) {
                for (ClassTeachingDayStResultDTO record : records) {
                    record.setTodayActivitySort(todaySortedMap.get(record.getClassId()));
                    record.setYesterdayActivitySort(todaySortedMap.size() + 1);
                }
            } else {
                for (ClassTeachingDayStResultDTO record : records) {
                    record.setTodayActivitySort(todaySortedMap.get(record.getClassId()));
                    if (yesterdaySortedMap.containsKey(record.getClassId())) {
                        record.setYesterdayActivitySort(yesterdaySortedMap.get(record.getClassId()));
                    } else {
                        record.setYesterdayActivitySort(todaySortedMap.size() + 1);
                    }
                }
            }
        }
    }

    /**
     * 查询 班级教学数据统计数据
     */
    @Override
    public List<ClassTeachingDayStResultDTO> find(ClassTeachingDayStQueryDTO query) {
        return classTeachingDayStManager.list(wrapper(query)).stream().map(classTeachingDayStConvert::convert).collect(Collectors.toList());
    }

    private LambdaQueryWrapper<ClassTeachingDayStEntity> wrapper(ClassTeachingDayStQueryDTO query) {
        LambdaQueryWrapper<ClassTeachingDayStEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(ClassTeachingDayStEntity::getId, v));
        Queries.accept(query.getSchoolNameList(), v -> wrapper.in(ClassTeachingDayStEntity::getSchoolName, v));
        return wrapper;
    }

    /**
     * 根据id查询 班级教学数据统计数据
     */
    @Override
    public ClassTeachingDayStResultDTO findById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return Optional.ofNullable(classTeachingDayStManager.findById(id)).map(classTeachingDayStConvert::convert).orElse(null);
    }

    /**
     * 新增 班级教学数据统计数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(@Valid ClassTeachingDayStCreateDTO dto) {
        ClassTeachingDayStEntity entity = classTeachingDayStConvert.create(dto);
        classTeachingDayStManager.save(entity);
        return entity.getId();
    }

    /**
     * 根据id修改 班级教学数据统计数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateById(@Valid ClassTeachingDayStUpdateDTO dto) {
        Optional.ofNullable(classTeachingDayStManager.getById(dto.getId())).orElseThrow(() -> CommonErrors.BAD_REQUEST.asException("数据不存在"));
        ClassTeachingDayStEntity entity = classTeachingDayStConvert.update(dto);
        return classTeachingDayStManager.updateById(entity);
    }

    /**
     * 根据id删除 班级教学数据统计数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        CommonErrors.BAD_REQUEST.check(Objects.nonNull(id), "ID不能为空");
        return classTeachingDayStManager.removeById(id);
    }

    /**
     * 根据id删除 班级教学数据统计数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(ClassTeachingDayStDeleteDTO dto) {
        return deleteById(dto.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateToday() {
        List<SchoolTeachingDayStEntity> schoolList = schoolTeachingDayStManager.list();
        if (CollectionUtils.isEmpty(schoolList)) {
            return;
        }
        //更新班级需要以学校作为前提
        List<String> schoolNameList = schoolList.stream().map(SchoolTeachingDayStEntity::getSchoolName).collect(Collectors.toList());
        this.updateClassTeachingToday(schoolNameList);
    }

    @Override
    public ClassOverviewResultDTO overview(ClassTeachingOverviewQueryDTO query) {
        return classTeachingDayStManager.overview(query);
    }

    /**
     * 更新学校对应的班级信息，注意这里的学校是100个一批
     *
     * @return Boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateClassTeachingToday(List<String> schoolNameList) {
        long batchSize = 1000;
        int currentPage = 1;

        while (true) {
            Page<ClassTeachingDayStEntity> page = new Page<>(currentPage, batchSize);
            //每次最多获取1000条，这里获取将会根据学校名字列表，同样这里获取的是课程模块的班级id，只是返回成了 ClassTeachingDayStEntity。
            IPage<ClassTeachingDayStEntity> pageList = classTeachingDayStManager.findPageBySchoolNameList(page, schoolNameList);

            if (pageList.getRecords().isEmpty()) {
                break;
            }

            //更新其他属性
            this.updateClassTeachingListToday(pageList.getRecords());

            // 没有下一页，退出循环
            if (!page.hasNext()) {
                break;
            }

            currentPage++;
        }

        return true;
    }

    /**
     * 为每个班级设置值并保存数量
     *
     * @param classList 班级列表
     */

    @Transactional(rollbackFor = Exception.class)
    public void updateClassTeachingListToday(List<ClassTeachingDayStEntity> classList) {

        LocalDate today = LocalDate.now();
        LocalDateTime todayStartTime = today.atTime(LocalTime.MIN);
        LocalDateTime todayEndTime = today.atTime(LocalTime.MAX);

        List<Long> courseClassIdList = classList.stream().map(ClassTeachingDayStEntity::getClassId).collect(Collectors.toList());

        //发布作业总数
        Map<Long, Integer> totalHomeworkCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.HOMEWORK.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布作业统计
        Map<Long, Integer> todayHomeworkCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.HOMEWORK.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布测评总数
        Map<Long, Integer> totalExamCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.EXAM.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布测评统计
        Map<Long, Integer> todayExamCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.EXAM.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布讨论总数
        Map<Long, Integer> totalDiscussCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.DISCUSS.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布讨论统计
        Map<Long, Integer> todayDiscussCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.DISCUSS.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布公告总数
        Map<Long, Integer> totalNoticeCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.NOTICE.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布公告统计
        Map<Long, Integer> todayNoticeCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.NOTICE.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布资料总数
        Map<Long, Integer> totalResourceCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.DATA.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布资料统计
        Map<Long, Integer> todayResourceCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.DATA.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布课件总数
        Map<Long, Integer> totalCoursewareCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.COURSEWARE.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布课件统计
        Map<Long, Integer> todayCoursewareCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.COURSEWARE.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //发布视频总数
        Map<Long, Integer> totalVideoCount = classTeachingDayStManager.findCourseContentCountByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.INTERACTIVE_VIDEO.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));
        //截止目前今日发布视频统计
        Map<Long, Integer> todayVideoCount = classTeachingDayStManager.findCurrentDateReleaseHomeworkByTypeAndCourseClassIdListAndDateRange(CourseContentTypeEnum.INTERACTIVE_VIDEO.getCode(), courseClassIdList, todayStartTime, todayEndTime).stream().collect(Collectors.toMap(ClassTeachingCountResultDTO::getClassId, ClassTeachingCountResultDTO::getCounts, (v1, v2) -> v2));

        //设置数量
        classList.forEach(clazz -> {
            if (Objects.isNull(clazz.getSchoolId())) {
                clazz.setSchoolId(0L);
            }
            clazz.setStatsDate(today);
            if (totalHomeworkCount.containsKey(clazz.getClassId())) {
                clazz.setTotalHomework(totalHomeworkCount.get(clazz.getClassId()));
            }

            if (todayHomeworkCount.containsKey(clazz.getClassId())) {
                clazz.setTodayHomework(todayHomeworkCount.get(clazz.getClassId()));
            }

            if (totalExamCount.containsKey(clazz.getClassId())) {
                clazz.setTotalExam(totalExamCount.get(clazz.getClassId()));
            }

            if (todayExamCount.containsKey(clazz.getClassId())) {
                clazz.setTodayExam(todayExamCount.get(clazz.getClassId()));
            }

            if (totalDiscussCount.containsKey(clazz.getClassId())) {
                clazz.setTotalDiscuss(totalDiscussCount.get(clazz.getClassId()));
            }

            if (todayDiscussCount.containsKey(clazz.getClassId())) {
                clazz.setTodayDiscuss(todayDiscussCount.get(clazz.getClassId()));
            }

            if (totalNoticeCount.containsKey(clazz.getClassId())) {
                clazz.setTotalNotice(totalNoticeCount.get(clazz.getClassId()));
            }

            if (todayNoticeCount.containsKey(clazz.getClassId())) {
                clazz.setTodayNotice(todayNoticeCount.get(clazz.getClassId()));
            }

            if (totalResourceCount.containsKey(clazz.getClassId())) {
                clazz.setTotalResource(totalResourceCount.get(clazz.getClassId()));
            }

            if (todayResourceCount.containsKey(clazz.getClassId())) {
                clazz.setTodayResource(todayResourceCount.get(clazz.getClassId()));
            }

            if (totalCoursewareCount.containsKey(clazz.getClassId())) {
                clazz.setTotalCourseware(totalCoursewareCount.get(clazz.getClassId()));
            }

            if (todayCoursewareCount.containsKey(clazz.getClassId())) {
                clazz.setTodayCourseware(todayCoursewareCount.get(clazz.getClassId()));
            }

            if (totalVideoCount.containsKey(clazz.getClassId())) {
                clazz.setTotalVideo(totalVideoCount.get(clazz.getClassId()));
            }

            if (todayVideoCount.containsKey(clazz.getClassId())) {
                clazz.setTodayVideo(todayVideoCount.get(clazz.getClassId()));
            }

        });

        classTeachingDayStManager.saveBatch(classList);
    }

}
